"""
This file is part of GSBEdit. For copyright and licensing information, please
see gsbedit.py in the GSBEdit base directory.
"""


import wx
from copy import deepcopy as copy
import ui_elements.display_panel as dp


class PanelTabset(wx.Panel):
    def __init__(self, parent, tab_list, next_id):
        wx.Panel.__init__(self, parent)
        self.main_sizer = wx.BoxSizer(wx.VERTICAL)
        self.parent = parent
        
        self.module_info = {}
        self.module_values = {}
        self.changed_module_values = {}
        self.conditions = []
        
        self.tabset = wx.Notebook(self)
        self.panels = []
        self.main_sizer.Add(self.tabset, 0, wx.EXPAND)
        
        self.SetSizer(self.main_sizer)
        
        self.next_id = self.set_tabs(tab_list, next_id)
    
    
    def get_next_id(self):
        return self.next_id
    
    
    def set_tabs(self, tab_list, next_id):
        self.Freeze()
        #self.tab_list = copy(tab_list)
        self.tab_list = tab_list
        
        for tab in self.tab_list:
            tab['dp'] = dp.DisplayPanel(self, tab['panel'], next_id, base_parent=self.tabset, prevent_freeze = True)
            next_id = tab['dp'].get_next_id()
        
        self.Thaw()
        
        return next_id
    
    
    def set_module(self, module_info, module_values):
        # Don't bother making a local copy. It's not needed for the module
        # info, and we *want* value changes to be seen globally.
        self.modue_info = module_info
        self.module_values = module_values
        self.changed_module_values = {}
        
        for tab in self.tab_list:
            tab['dp'].reset_displayed_values()
            tab['dp'].set_module(module_info, module_values)
            if 'condition' in tab:
                self.conditions.append(panel['condition'])
        
        self.update_display()
    
    
    def update_display(self):
        self.Freeze()
        #self.tabset.DeleteAllPages()    # <<<<< DAMMIT KEMP
        for i in reversed(range(self.tabset.GetPageCount())):
            self.tabset.RemovePage(i)

        i = 0
        for tab in self.tab_list:
            if self.should_display_child(tab):
                self.tabset.AddPage(tab['dp'], tab['name'])
                tab['dp'].Show()
                self.tabset.ChangeSelection(i)  # HACKY
                i += 1
            else:
                tab['dp'].Hide()
        
        if self.tabset.GetPageCount() > 0: self.tabset.ChangeSelection(0) # HACKY
        
        self.Thaw()
        self.Layout()


    def evaluate_condition(self, condition, values=None):
        if values == None:
            values = self.get_current_values()
        
        key, op, value = condition.split(' ')
        
        # For now we only deal with equality
        if op == '=':
            if key in values:
                if values[key] == value:
                    return True
            else:
                print >> sys.stderr, "Unknown key: %s" % key
            
        else:
            print >> sys.stderr, "Invalid condition: %s" % condition
            
        return False
    
    
    def should_display_child(self, tab):
        """Check if a child panel should be displayed.
        
        Internal function, not intended for external callers.
        """
        t1 = True
        if 'condition' in tab:
            t1 = self.evaluate_condition(tab['condition'])
        t2 = tab['dp'].should_display()
        
        if t2 == None:
            return None
        
        return t1 and t2
    
    
    def evt_value_updated(self, key, value, sender=None):
        previous_values = self.get_current_values()
        new_values = copy(previous_values)
        self.update_dict(new_values, {key:value})
    
        if key in self.module_values:
            # A value we have an original for
            original_value = self.module_values[key]
            if key in self.changed_module_values:
                # Has been previously changed
                old_value = self.changed_module_values[key]
                
                if value == original_value:
                    # Changed back to the original
                    del self.changed_module_values[key]
                else:
                    # Changed from the original
                    self.changed_module_values[key] = value
            
            else:
                # Hasn't been previously changed
                if value == original_value:
                    # Hasn't actually changed (e.g. control creation)
                    pass
                else:
                    # First change for this value
                    self.changed_module_values[key] = value
        else:
            # A new value. We don't care if it's already in
            # self.changed_module_values, we need to store it.
            self.changed_module_values[key] = value
        
        # Do our own checks regarding whether to call update_display
        if self.has_condition_changed(previous_values, new_values):
            self.update_display()
        
        # Pass the event along the chain
        if sender != self.parent:
            self.parent.evt_value_updated(key, value, self)
        
        for panel in self.panels:
            if panel['object'] != sender:
                panel['object'].evt_value_updated(key, value, self)
        

    def have_values_changed(self):
        return len(copy(self.changed_module_values)) > 0
    
    
    def get_changed_values(self):
        return copy(self.changed_module_values)
    
    
    def get_current_values(self):
        new = copy(self.module_values)
        self.update_dict(new, self.get_changed_values())
        return new
    
    
    def has_condition_changed(self, previous_values, new_values):
        for condition in self.conditions:
            prev_result = self.evaluate_condition(condition, previous_values)
            new_result = self.evaluate_condition(condition, new_values)
            if prev_result != new_result:
                return True
        return False
    
    
    def update_dict(self, target, new_values):
        for key,value in new_values.iteritems():
            if value == None and key in target:
                del target[key]
            else:
                target[key] = value


    def save_values(self):
        self.update_dict(self.module_values, self.get_changed_values())
        self.changed_module_values = {}
        for panel in self.panels:
            panel.save_values()
    
    """
    def restore_values(self):
        for key,value in self.current_values.iteritems():
            if key in self.controls:
                self.controls[key] = value
    """
    
